package com.wonders;

import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


/**
 * 配置asyncSupported = true，告诉容器这个Servlet支持异步处理。
 *
 * 对于异步上下文对象结束的方式：
 *      1、在异步子线程这使用asyncContext.complete()方法：该方法表示完
 * 成该请求上的异步操作，并关闭用于初始化当前异步对象的响应。
 *      2、在异步子线程中使用asyncContext.dispatch()方法：该方法将请求和
 * 响应的控制权委托给调度目标，并且在调度目标完成执行后将关闭响应。在结束异步
 * 操作的同时，会将参数所指定的页面内容包含到当前异步对象相关的标准输出流中。
 * 其执行效果相当于RequestDispatcher对象的include()方法的执行效果。
 *      3、在异步Servlet主线程中设置asyncContext的超时时限，当超时时限到达时，
 * 完成异步操作，并关闭用于初始化当前异步对象的响应。
 */
@WebServlet(value = "/AsyncServlet3", asyncSupported = true)
public class AsyncServlet3 extends HttpServlet {
    ExecutorService executorService = Executors.newFixedThreadPool(10);

    /**
     * 对于每一个请求，Servlet会使用原生的请求和响应初始化AsyncContext，并释放容器所分配的线程，响应被延后。
     * 对于这些被延后的响应的请求，创建一个实现Runnable接口的对象Task，Task用于处理我们耗时的任务。并且
     * 创建一个线程池，线程池的数量固定，让这些必须长时间处理的请求，在这些有限数量的线程中完成，而不用
     * 每次请求都占用容器分配的线程。
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter out = resp.getWriter();
        out.append("主线程开始运行<br>");
        AsyncContext asyncContext = req.startAsync();
        executorService.submit(new Task1(asyncContext));
//        asyncContext.start(new Task1(asyncContext)); // 如果不使用线程池，可以AsyncContext#start方法启动异步任务
        out.append("主线程运行结束<br>");
    }

    @Override
    public void destroy() {
        executorService.shutdown();
    }
}
